package com.meatball.core.config

import com.meatball.core.exception.AttributeMismatchWarning
import com.meatball.core.exception.DataAlreadyExistsException
import com.meatball.core.exception.InvalidTokenException
import com.meatball.core.exception.TokenExpiredException
import org.springframework.http.HttpStatus
import org.springframework.validation.BindException
import org.springframework.validation.ObjectError
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestControllerAdvice
import org.springframework.web.multipart.MaxUploadSizeExceededException
import java.util.function.Consumer

/**
 * 全局异常捕获
 * @author 张翔宇
 * @since 2021年12月8日13点21分
 * @version 1.0
 */
@RestControllerAdvice
class RestExceptionHandler {
    @ExceptionHandler
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    fun exception(e: BindException): BaseResponse {
        return BaseResponse.error(
            HttpStatus.BAD_REQUEST.value(),
            getErrorMessage(e.allErrors)
        )
    }

    @ExceptionHandler
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    fun exception(e: MethodArgumentNotValidException): BaseResponse {
        return BaseResponse.error(
            HttpStatus.BAD_REQUEST.value(),
            getErrorMessage(e.bindingResult.allErrors)
        )
    }

    @ExceptionHandler
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    fun exception(e: MaxUploadSizeExceededException?): BaseResponse {
        return BaseResponse.error(HttpStatus.BAD_REQUEST.value(), "超出最大文件上传大小")
    }

    @ExceptionHandler
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    fun exception(e: TokenExpiredException): BaseResponse {
        return BaseResponse.error(HttpStatus.UNAUTHORIZED.value(), e.message ?: "")
    }

    @ExceptionHandler
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    fun exception(e: InvalidTokenException): BaseResponse {
        return BaseResponse.error(HttpStatus.UNAUTHORIZED.value(), e.message ?: "")
    }

    @ExceptionHandler(IllegalArgumentException::class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    fun handleIllegalArgumentException(e: IllegalArgumentException): BaseResponse {
        return BaseResponse.error(HttpStatus.BAD_REQUEST.value(), e.message ?: "")
    }

    @ExceptionHandler(DataAlreadyExistsException::class)
    @ResponseStatus(HttpStatus.CONFLICT)
    fun handleDataAlreadyExistsException(e: DataAlreadyExistsException): BaseResponse {
        return BaseResponse.error(HttpStatus.CONFLICT.value(), e.message ?: DATA_ALREADY_EXISTS)
    }

    @ExceptionHandler(AttributeMismatchWarning::class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    fun handleAttributeMismatchWarning(e: AttributeMismatchWarning): BaseResponse {
        return BaseResponse.error(HttpStatus.NOT_FOUND.value(), e.message ?: "")
    }

//    @ExceptionHandler
//    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
//    fun exception(e: Exception): BaseResponse {
//        return BaseResponse.error(
//            HttpStatus.INTERNAL_SERVER_ERROR.value(),
//            e.message ?: ""
//        )
//    }

    /**
     * 格式化参数错误信息
     * @param e 异常
     * @return message
     */
    private fun getErrorMessage(e: List<ObjectError>): String {
        val builder = StringBuilder()
        e.forEach(Consumer { item: ObjectError ->
            if (builder.isNotEmpty()) {
                builder.append("，")
            }
            builder.append(item.defaultMessage)
        })
        builder.append("。")
        return builder.toString()
    }
}
